%{
#include <stdlib.h>
#include <stdio.h>
#include "../src/types.h"


extern int line_num;

extern int yylex();
extern int yyparse();
extern FILE* yyin;

command_c* command_array = NULL;
int* c_array_length = NULL;


void yyerror(const char* s);
%}

%union {
	char cval;
	int ival;
}

%token<ival> T_NUMBER
%token<cval> T_REG

%token T_NEWLINE

%token T_PUSH 	// PUSH <num> onto the stack
%token T_POP 	// POP <reg> pop top of stack into register
%token T_ADD 	// POP off 2 items on the stack and PUSH their sum into the stack
%token T_IFEQ 	// if top of stack is 0, continue. else, JUMP to <address> where <address> is a line number
%token T_JUMP 	// jump to a line number
%token T_PRINT 	// print the value on the top of the stack
%token T_DUP 	// PUSH a copy of what's on the top of the stack back onto the stack

%start machine

%%

machine:
	body_lines
	;
body_lines:
	body_lines body_line 
	| body_line
	;
body_line: // theres probably a MUCH better way to do this than Im doing...
	T_NEWLINE 
	| T_NEWLINE T_NEWLINE {
		command_c command;
		command.type = NO_OP;
		command_array[line_num - 2] = command;
		}
	| T_PUSH T_NUMBER 	{
		command_c command;
		command.type = PUSH;
		command.push_d.num = $2;
		command_array[line_num - 1] = command;
		}
	| T_POP T_REG 	{
		command_c command;
		command.type = POP;
		command.pop_d.reg = $2;
		command_array[line_num - 1] = command;
		}
	| T_ADD 	{
		command_c command;
		command.type = ADD;
		command_array[line_num - 1] = command;
		}
	| T_IFEQ T_NUMBER	{
		command_c command;
		command.type = IFEQ;
		command.ifeq_d.address = $2;
		command_array[line_num - 1] = command;
		}
	| T_JUMP T_NUMBER	{
		command_c command;
		command.type = JUMP;
		command.jump_d.address = $2;
		command_array[line_num - 1] = command;
		}
	| T_PRINT 	{
		command_c command;
		command.type = PRINT;
		command_array[line_num - 1] = command;
		}
	| T_DUP 	{
		command_c command;
		command.type = DUP;
		command_array[line_num - 1] = command;		
		}
	;

%%

void parse_to_array(command_c** array, int* inputLength, FILE** file) {
	yyin = *file;
	command_array = *array;
	c_array_length = inputLength;
	increaseArray(&*command_array, c_array_length); // note for some reason this causes a seg fault when placed in the above part... :\

	do { 
		yyparse();
	} while(!feof(yyin));

	command_c command;
	command.type = END;
	command_array[line_num - 1] = command; // adding the end command we know the stream is done with and over with and	
	
}

void yyerror(const char* s) {
	fprintf(stderr, "Parse error: %s\n", s);
	exit(1);
}
